package oauth

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"gitee.com/liuqiaosz/gokits/utils"
	jsoniter "github.com/json-iterator/go"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

type oauthClient struct {
}

type TokenInfo struct {
	AccessToken string `json:"access_token"`
	TokenType   string `json:"token_type"`
	Expire      int64  `json:"expires_in"`
	Scope       string `json:"scope"`
}

type Response struct {
	ClientId string   `json:"client_id"`
	Aud      []string `json:"aud"`
	Scope    []string `json:"scope"`
	Active   bool     `json:"active"`
	Expired  int64    `json:"exp"`
}

var client *oauthClient

func GetOauthClient() *oauthClient {
	client = &oauthClient{}
	return client
}

func (c *oauthClient) GetToken(serverUrl string, appId string, appSecret string) (*TokenInfo, error) {
	bodyReader := bytes.NewReader([]byte(fmt.Sprintf("grant_type=client_credentials&scope=read&client_id=%s&client_secret=%s", appId, appSecret)))
	request, err := http.NewRequest("POST", serverUrl, bodyReader)
	if nil != err {
		return nil, err
	}
	requestCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	response, err := http.DefaultClient.Do(request.WithContext(requestCtx))
	var buffer *bytes.Buffer

	defer func() {
		if nil != response {
			response.Body.Close()
		}

		if nil != buffer {
			utils.GetBuffPool().Put(buffer)
		}
	}()

	if nil != err {
		if nil != cancel {
			cancel()
		}
		return nil, err
	}

	buffer = utils.GetBuffPool().Get()
	if _, err := io.Copy(buffer, response.Body); err != nil {
		return nil, err
	}
	responseBody := buffer.Bytes()

	if response.StatusCode != http.StatusOK {
		return nil, errors.New(fmt.Sprintf("Http error code[%d] message[%s]", response.StatusCode, string(responseBody)))
	}

	token := TokenInfo{}
	if err := jsoniter.Unmarshal(responseBody, &token); err != nil {
		return nil, err
	}

	return &token, nil
}

func (c *oauthClient) CheckToken(server string, token string, service string) (bool, error) {
	sourceName := service
	if strings.Index(sourceName, "/") == 0 {
		sourceName = service[1:]
	}

	requestUrl := fmt.Sprintf("%s/oauth/check_token?token=%s", server, token)
	fmt.Println(fmt.Sprintf("发起OAUTH服务Token校验,请求服务URL[%s],目标服务名[%s]", requestUrl, sourceName))
	resp, err := http.Get(requestUrl)
	if err != nil {
		return false, err
	}
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return false, err
	}
	result := Response{}
	if err := jsoniter.Unmarshal(data, &result); err != nil {
		return false, err
	}
	for _, v := range result.Aud {
		if v == sourceName {
			return true, nil
		}
	}
	return false, errors.New("Dont have Permission")
}
